package pCloud.crypto.kpabe;

public class KPAbe {
	static {
		System.loadLibrary("proxyKPAbe");
	}

	// data owner API. Assume one sliding window size per owner.
	public native byte[] initOwner(String[] attributeUniverse, int beta);

	public native byte[] enc_simple(String[] attributes, int value);

	// index of the record in the stream 0,1,2...
	public native byte[] enc_slidingWindow(String[] attributes, int value,
			int index);

	public native byte[] extractOriginalCipher(byte[] cipher);

	// the TK used by the cloud
	public native byte[] generateTransformKey(String policy, int policyId);

	// zu
	public native byte[] generateUserDecryptionKey(int policyId);

	// sigma(alpha,beta)
	public native byte[] generateUserMaskValue(int alpha);

	// data user API.
	public native void initUser_simple(byte[] pubK, byte[] tK, byte[] decK);

	public native void initUser_slidingWindow(byte[] pubK, byte[] tK,
			byte[] decK, byte[] mask, int beta);

	// pre-compute discrete-log solution: g^x -> x
	public native void initDiscreteLogMap(int max);

	// return -1 if invalid decryption, plaintext value otherwise
	public native int decrypt_simple(byte[] transformedCipher,
			byte[] originalCipher);

	public native int decrypt_slidingWindow(byte[] transformedCipher,
			byte[] originalCipher, int windowIndex);

	// cloud API. Each public parameter is mapped to a streamId, each user a
	// policyId
	public native void initACInstance(byte[] pubK, int streamId,
			byte[] transformK, int policyId);

	public synchronized native byte[] transform_simple(byte[] ciphertext, int streamId,
			int policyId);

	public synchronized native byte[] multiplyCiphers(byte[][] ciphertexts, int streamId);

	public static void main(String[] argv) {
		System.out.println("Hello world");
		String[] universe = new String[1];
		universe[0] = "x";

		String[] atts = new String[1];
		atts[0] = "x";
		KPAbe abeHandler = new KPAbe();
		long overallStart = System.currentTimeMillis();

		long ownerStart = System.currentTimeMillis();
		byte[] pubK = abeHandler.initOwner(universe, 2);
		long ownerEnd = System.currentTimeMillis();
		System.out.println("Onwer init time = " + (ownerEnd - ownerStart));
		byte[] userK = abeHandler.generateUserDecryptionKey(0);
		byte[] tK = abeHandler.generateTransformKey("x", 0);
		byte[] mask = abeHandler.generateUserMaskValue(2);
		
		byte[] cipher0 = abeHandler.enc_slidingWindow(atts, 250, 0);
		byte[] cipher1 = abeHandler.enc_slidingWindow(atts, 25, 1);
		
		byte[] ep0 = abeHandler.extractOriginalCipher(cipher0);
		byte[] ep1 = abeHandler.extractOriginalCipher(cipher1);
		
		
		long start = System.currentTimeMillis();
		abeHandler.initACInstance(pubK, 0, tK, 0);
		long end = System.currentTimeMillis();
		System.out.println("init cloud time = " + (end - start));

		start = System.currentTimeMillis();
		byte[] transformedCipher0 = abeHandler.transform_simple(cipher0, 0, 0);
		byte[] transformedCipher1 = abeHandler.transform_simple(cipher1, 0, 0);
		byte[][] cphs = new byte[2][transformedCipher0.length];
		cphs[0] = transformedCipher0;
		cphs[1] = transformedCipher1;
		byte[] tc = abeHandler.multiplyCiphers(cphs, 0);
		
		byte[][] eps = new byte[2][ep0.length];
		eps[0] = ep0;
		eps[1] = ep1;
		byte[] es = abeHandler.multiplyCiphers(eps, 0);
		
		end = System.currentTimeMillis();
		System.out.println("transform time = " + (end - start));

		start = System.currentTimeMillis();		
		abeHandler.initUser_slidingWindow(pubK, tK, userK, mask, 2);
		end = System.currentTimeMillis();
		System.out.println("init user time = " + (end - start));

		System.out.println("Decryption result = "
				+ abeHandler.decrypt_slidingWindow(tc, es,0));
		long overallEnd = System.currentTimeMillis();
		System.out.println("Overall time = " + (overallEnd - overallStart));
		
		
		cipher0 = abeHandler.enc_slidingWindow(atts, 200, 2);
		cipher1 = abeHandler.enc_slidingWindow(atts, 25, 3);
		
		ep0 = abeHandler.extractOriginalCipher(cipher0);
		ep1 = abeHandler.extractOriginalCipher(cipher1);
		
		transformedCipher0 = abeHandler.transform_simple(cipher0, 0, 0);
		transformedCipher1 = abeHandler.transform_simple(cipher1, 0, 0);
		cphs = new byte[2][transformedCipher0.length];
		cphs[0] = transformedCipher0;
		cphs[1] = transformedCipher1;
		tc = abeHandler.multiplyCiphers(cphs, 0);
		
		eps = new byte[2][ep0.length];
		eps[0] = ep0;
		eps[1] = ep1;
		es = abeHandler.multiplyCiphers(eps, 0);
		System.out.println("Decryption result = "
				+ abeHandler.decrypt_slidingWindow(tc, es,0));
	}
}
